/*
 * Implementation of encoding request in CBOR format
 *
 * Copyright (c) Huawei Technologies Co., Ltd. 2022. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */
#include "qtsm_cbor_msg.h"

static bool cbor_req_type(cbor_item_t *root, const req_type *objp)
{
    cbor_item_t *cur = NULL;
    bool rc;

    if (!objp)
        return false;

    cur = cbor_build_uint32(*objp);
    if (!cur)
        return false;
    rc = cbor_array_push(root, cbor_move(cur));

    return rc;
}

static bool cbor_req_describe_pcr(cbor_item_t *root,
                                  const req_describe_pcr *objp)
{
    cbor_item_t *cur = NULL;
    bool rc;

    if (!objp)
        return false;

    /* index */
    cur = cbor_build_uint16(objp->index);
    if (!cur)
        return false;
    rc = cbor_array_push(root, cbor_move(cur));

    return rc;
}

static bool cbor_req_extend_pcr(cbor_item_t *root,
    const req_extend_pcr *objp)
{
    cbor_item_t *cur = NULL;
    bool rc;

    if (!objp || !(objp->data))
        return false;

    /* index */
    cur = cbor_build_uint16(objp->index);
    if (!cur)
        return false;
    rc = cbor_array_push(root, cbor_move(cur));
    if (!rc)
        goto err;

    /* data */
    cur = cbor_build_bytestring(objp->data, objp->data_len);
    if (!cur) {
        rc = false;
        goto err;
    }
    rc = cbor_array_push(root, cbor_move(cur));

err:
    return rc;
}

static bool cbor_req_lock_pcr(cbor_item_t *root,
    const req_lock_pcr *objp)
{
    cbor_item_t *cur = NULL;
    bool rc;

    /* index */
    cur = cbor_build_uint16(objp->index);
    if (!cur)
        return false;
    rc = cbor_array_push(root, cbor_move(cur));

    return rc;
}

static bool cbor_req_lock_pcrs(cbor_item_t *root,
    const req_lock_pcrs *objp)
{
    cbor_item_t *cur = NULL;
    cbor_item_t *array_root = NULL;
    uint32_t i;
    bool rc;

    if (!objp || !(objp->range))
        return false;

    /* range */
    array_root = cbor_new_definite_array(objp->count);
    if (!array_root)
        return false;

    for (i = 0; i < objp->count; i++) {
        cur = cbor_build_uint16(*(objp->range + i));
        if (!cur) {
            rc = false;
            goto err;
        }
        rc = cbor_array_push(array_root, cbor_move(cur));
        if (!rc)
            goto err;
    }

    rc = cbor_array_push(root, cbor_move(array_root));

err:
    return rc;
}

static bool cbor_req_attestation(cbor_item_t *root,
    const req_attestation *objp)
{
    cbor_item_t *cur = NULL;
    bool rc = true;

    if (!objp)
        return false;

    /* user_data */
    if (objp->user_data) {
        cur = cbor_build_bytestring(objp->user_data, objp->user_data_len);
        if (!cur)
            return false;
    } else {
        cur = cbor_new_definite_bytestring();
    }

    rc = cbor_array_push(root, cbor_move(cur));
    if (!rc)
        goto err;

    /* nonce */
    if (objp->nonce) {
        cur = cbor_build_bytestring(objp->nonce, objp->nonce_len);
        if (!cur) {
            rc = false;
            goto err;
        }
    } else {
        cur = cbor_new_definite_bytestring();
    }

    rc = cbor_array_push(root, cbor_move(cur));
    if (!rc)
        goto err;

    /* pubkey */
    if (objp->pubkey) {
        cur = cbor_build_bytestring(objp->pubkey, objp->pubkey_len);
        if (!cur) {
            rc = false;
            goto err;
        }
    } else {
        cur = cbor_new_definite_bytestring();
    }

    rc = cbor_array_push(root, cbor_move(cur));

err:
    return rc;
}

bool cbor_qtsm_message_req(cbor_item_t *root, const qtsm_message_req *objp)
{
    if (!cbor_req_type(root, &objp->type))
        return false;

    switch (objp->type) {
        case DESCRIBE_PCR:
            if (!cbor_req_describe_pcr(root, &objp->qtsm_message_req_u.describe_pcr))
                return false;
            break;
        case EXTEND_PCR:
            if (!cbor_req_extend_pcr(root, &objp->qtsm_message_req_u.extend_pcr))
                return false;
            break;
        case LOCK_PCR:
            if (!cbor_req_lock_pcr(root, &objp->qtsm_message_req_u.lock_pcr))
                return false;
            break;
        case LOCK_PCRS:
            if (!cbor_req_lock_pcrs(root, &objp->qtsm_message_req_u.lock_pcrs))
                return false;
            break;
        case DESCRIBE_QTSM:
            break;
        case ATTESTATION:
            if (!cbor_req_attestation(root, &objp->qtsm_message_req_u.attestation))
                return false;
            break;
        default:
            return false;
    }

    return true;
}
